﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Wizard.Compiler
{
    using System.Reflection;
    using Wizard.Source;

    public class CompilerEngine : Wizard.ICompilerEngine
    {
        #region ICompiler Members
       
        private Wizard.Source.IWizardApplication mApplication;
        private Wizard.IWizardEngine mWizardEngine;
        internal IDictionary<string, StatementInfo> mStatementInfos;
        //private readonly Dictionary<string, PluginStatement> mStatements;


        public CompilerEngine()
        {
        }

        void Wizard.ICompilerEngine.Compile(Wizard.Source.IWizardApplication application)
        {
            mApplication = application;
            mApplication.DeleteClassSources(mWizardEngine.DataStore);

            Parsers.WizardParser p = new Wizard.Compiler.Parsers.WizardParser(this);

            foreach (var s in mApplication.GetSourceFiles())
            {
                string filename=String.Format("#{0}: {1}",s.SourceFileId,s.FileName);
                p.CompileSourceText(mApplication, filename, s.SourceText, Wizard.Compiler.Tokenizers.Language.Basic);
            }

        }

        #endregion

        //    private IDataStore mDataStore;
        //    private ICompiler mCompiler;

        //    //private string mPluginFolder;
        //    public readonly EngineType mApplicationType;
        //    //private readonly Dictionary<int, RunningMethod> mRunningMethods;
        //    //private readonly Dictionary<int, MethodSource> mMethods;
        //    //public readonly NamespaceCollection Namespaces;
        //    //public readonly SessionsCollection RuntimeSessions;


        //    protected IWizardEngine(EngineType type)
        //    {
        //    }

        //    protected abstract string InternalGetPluginFolder();

        //    public IDataStore DataStore
        //    {
        //        get
        //        {
        //            return mDataStore;
        //        }
        //        set
        //        {
        //            mDataStore = value;
        //        }
        //    }

        //    public ICompiler Compiler
        //    {
        //        get
        //        {
        //            return mCompiler;
        //        }
        //        set
        //        {
        //            mCompiler = value;
        //        }
        //    }

        //private void RegisterAssembly(Assembly assembly)
        //{
        //    Type IStatementOfApplication = typeof(CompilerEngine).GetGenericTypeDefinition();
        //    foreach (var t in assembly.GetTypes())
        //    {
        //        if (t.IsClass && !t.IsAbstract)
        //        {
        //            var isStatement = (typeof(Statements.Statement).IsAssignableFrom(t));

        //            if (isStatement)
        //            {
        //                var statementName = t.Name;
        //                //                            0123456789
        //                if (statementName.StartsWith("Statement")) statementName = statementName.Substring(9);
        //                mStatementInfos.Add(statementName, new StatementInfo(t));
        //            }
        //        }
        //    }
        //}

        //    //public void Run(MethodSource methodSource)
        //    //{
        //    //    var Instance = new Runtime.MethodInstance(methodSource);
        //    //    //Instance.Run();
        //    //}


        //    public virtual StringComparer StringComparer
        //    {
        //        get { return StringComparer.OrdinalIgnoreCase; }
        //    }

        //    //protected virtual string PluginFolder
        //    //{
        //    //    get { return mPluginFolder; }
        //    //}

        //    #region IDisposable Members

        //    void IDisposable.Dispose()
        //    {
        //        foreach (var plugin in mPlugins)
        //        {
        //            try
        //            {
        //                if (plugin.mPlugin != this) plugin.mPlugin.Dispose();
        //            }
        //            catch (Exception)
        //            {
        //            }
        //        }
        //    }

        //    #endregion


        //    protected abstract bool AcceptPlugin(string pluginName);

        //    protected virtual void PluginLoaded(IPlugin plugin)
        //    {
        //        // nothing here but overridable
        //    }

        //    //internal bool TryGetStatementType(string statementName, ref PluginStatement statementType)
        //    //{
        //    //    var statement = mStatements[statementName];
        //    //    if (statement == null) return false;

        //    //    statementType = statement;
        //    //    return true;
        //    //}

        //    //public RunningMethod StartMethod(MethodSource Method, object applicationContext)
        //    //{
        //    //    var runningMethod = GetNewRunningMethod(Method);
        //    //    Interpretor.RunForward(runningMethod, applicationContext);
        //    //    return runningMethod;
        //    //}

        //    //protected internal abstract void MethodIsWaitingForUser(StatementArgs runContext);
        //    //protected internal abstract void MethodIsFinished(StatementArgs runContext);
        //    //protected internal abstract void MethodIsClosed(StatementArgs runContext);

        //    //public MethodSource GetMethodSourceById(int methodId)
        //    //{
        //    //    MethodSource runResult;
        //    //    if (mMethods.TryGetValue(methodId, out runResult)) return runResult;
        //    //    return null;
        //    //}

        //    //public IEnumerable<MethodSource> GetMethodList()
        //    //{
        //    //    return mMethods.Values;
        //    //}

        //    //private RunningMethod GetNewRunningMethod(MethodSource Method)
        //    //{
        //    //    var runResult = new RunningMethod(Method, null);
        //    //    mRunningMethods[runResult.RunningMethodId] = runResult;
        //    //    return runResult;
        //    //}

        //    //public RunningMethod GetRunningMethodById(int runningMethodId)
        //    //{
        //    //    return mRunningMethods[runningMethodId];
        //    //}


        //    public abstract string FriendlyName { get; }

        //    void IPlugin.Load(IWizardEngine engine)
        //    {

        //    }

        //    void IPlugin.Init()
        //    {
        //    }


        private void FindStatements()
        {
            mStatementInfos = new Dictionary<string, StatementInfo>(System.StringComparer.OrdinalIgnoreCase);
            var iStatementType = typeof(IStatement);
            foreach (var plugin in this.mWizardEngine.RuntimeEngine.LoadedPlugins)
            {
                var assembly1 = plugin.GetType().Assembly;

                foreach (var type1 in assembly1.GetTypes())
                {
                    //Trace.WriteLine(assembly1.FullName + " " + type1.Name);
                    if (type1.IsAbstract == false
                        && type1.IsClass
                        && iStatementType.IsAssignableFrom(type1))
                    {
                        //var newstatement = new PluginStatement(loadedPlugin, type1);
                        //TODO : check if the Statement has a public parameter-less constructor
                        //TODO : check if the Statement is designed for this application type
                        //TODO : check if there is another Statement with that name already
                        mStatementInfos.Add(type1.Name, new StatementInfo(type1));
                    }
                }
                // if we reach this point we keep the plugin in the list
                //idx++;
            }
        }

        //private void FindPluginFolder()
        //{
        //    //mPluginFolder = InternalGetPluginFolder();
        //    //mPlugins.Add(new LoadedPlugin(this, this.GetType().Assembly));

        //    //if (PluginFolder == null) return;

        //    //var dir = new DirectoryInfo(PluginFolder);

        //    //if (!dir.Exists) return;

        //    //foreach (var fileInfo1 in dir.GetFiles("Wizard.*.dll"))
        //    //{
        //    //    var accept = false;
        //    //    var pluginName = Path.GetFileNameWithoutExtension(fileInfo1.Name).ToLower();

        //    //    switch (pluginName)
        //    //    {
        //    //        case "wizard.common":
        //    //        case "wizard.asp":
        //    //        case "wizard.console":
        //    //        case "wizard.forms":
        //    //            accept = false;
        //    //            break;

        //    //        default:
        //    //            accept = AcceptPlugin(pluginName);
        //    //            break;
        //    //    }


        //    //    if (accept)
        //    //    {
        //    //        var nbPluginInThisAssembly = 0;
        //    //        var assembly1 = Assembly.LoadFrom(fileInfo1.FullName);
        //    //        var iPluginType = typeof(IPlugin);

        //    //        foreach (var type1 in assembly1.GetTypes())
        //    //        {
        //    //            if (type1.IsAbstract == false
        //    //                && type1.IsClass
        //    //                && iPluginType.IsAssignableFrom(type1))
        //    //            {
        //    //                try
        //    //                {
        //    //                    nbPluginInThisAssembly++;
        //    //                    var o = Activator.CreateInstance(type1);
        //    //                    var plugin = o as IPlugin;
        //    //                    if (plugin != null)
        //    //                    {
        //    //                        mPlugins.Add(new LoadedPlugin(plugin, assembly1));
        //    //                        PluginLoaded(plugin);
        //    //                    }
        //    //                }
        //    //                catch (Exception ex)
        //    //                {
        //    //                    throw new WizardException(String.Format("Cannot instantiate type {0}\n{1}",
        //    //                                                            type1.Name, ex.ToString()));
        //    //                }
        //    //            }
        //    //        }
        //    //        if (nbPluginInThisAssembly == 0)
        //    //        {
        //    //            throw new WizardException(
        //    //                string.Format(
        //    //                    "Assembly {0} does not contain any plugin and therefore should not be there.",
        //    //                    fileInfo1.FullName));
        //    //        }
        //    //    }
        //    //}            
        //}

        #region IPlugin Members

        string Wizard.Runtime.IPlugin.FriendlyName
        {
            get { throw new NotImplementedException(); }
        }

        void Wizard.Runtime.IPlugin.Load()
        {
        }

        void Wizard.Runtime.IPlugin.Initialize(IWizardEngine wizardEngine)
        {
            mWizardEngine = wizardEngine;
            FindStatements();
        }

        #endregion
    }
}
